// 基于Node写出一静态服务器。接收请求并且响应特定目录(服务器目录)中的html、css、js、图片等资源
const http = require('http')
const path = require('path')
const mime = require('mime') // 处理相应类型
const url = require('url')
const fs = require('fs').promises
const { createReadStream } = require('fs')
const ejs = require('ejs')
const {promisify} = require('util')

function mergeConfig(config) {
  return {
    port: 8888,
    directory: process.cwd(),
    ...config,
  }
}

class Server {
  constructor(config) {
    this.config = mergeConfig(config)
  }
  start() {
    let server = http.createServer(this.handleServer.bind(this))
    server.listen(this.config.port, () => {
      console.log(`server is running port ${this.config.port}`)
    })
  }
  async handleServer(req, res) {
    let { pathname } = url.parse(req.url)
    pathname = decodeURIComponent(pathname)
    let absPath = path.join(this.config.directory, pathname)
    // 判断文件类型，文件是否存在等
    try {
      let statObj = await fs.stat(absPath)
      if (statObj.isFile()) {
        this.handleFile(req, res, absPath)
      } else {
        let dirs = await fs.readdir(absPath)
        dirs = dirs.map((item) => {
          return {
            path: path.join(pathname, item),
            dirs: item
          }
        })
        let renderFile = promisify(ejs.renderFile)

        let parentpath = path.dirname(pathname)

        let ret = await renderFile(path.resolve(__dirname, 'template.html'), {
          arr: dirs,
          parent: pathname == '/' ? false : true,
          parentpath,
          title: path.basename(absPath)
        })
        res.end(ret)
      }
    } catch (e) {
      console.log(e)
      this.handleError(req, res, e)
    }
  }
  handleError(req, res, err) {
    res.statusCode = 404
    res.setHeader('Content-type', 'text/html;charset=utf-8')
    res.end('Not Found')
  }
  handleFile(req, res, absPath) {
    res.statusCode = 200
    res.setHeader('Content-type', mime.getType(absPath) + ';charset=utf-8')
    createReadStream(absPath).pipe(res)
  }
}

const lgServer = new Server()
lgServer.start()
